package com.wg.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wg.R;
import com.wg.entity.*;
import com.wg.entity.dto.SubTaskUpdateVo;
import com.wg.entity.dto.SubTaskVo;
import com.wg.entity.dto.WgInfoAddDto;
import com.wg.entity.vo.PageVo;
import com.wg.mapper.WgInfoMapper;
import com.wg.service.*;
import com.wg.utils.WgUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class WgInfoServiceImpl extends ServiceImpl<WgInfoMapper, WgInfos> implements WgInfoService {

    @Autowired
    UserService userService;
    @Autowired
    SubtaskService subtaskService;

    @Autowired
    WgInfoMapper wgInfoMapper;

    @Autowired
    FocusService focusService;

    @Autowired
    ScoreService scoreService;

    @Autowired
    ApplyService applyService;

    @Autowired
    DeptService deptService;

    @Override
    public R<PageVo<WgInfos>> findAll(Integer pageSize, Integer pageNum) {
        LambdaQueryWrapper<WgInfos> queryWrapper = new LambdaQueryWrapper<>();
        Page<WgInfos> wgPage = new Page<>(pageNum, pageSize);
        page(wgPage, queryWrapper);
        List<WgInfos> records = wgPage.getRecords();
        // 封装一些信息
        records = putInfo(records);
        PageVo<WgInfos> pageVo = new PageVo<>(records, wgPage.getTotal());
        return R.ok(pageVo);
    }

    @Override
    public R<PageVo<WgInfos>> findOwnedWGById(Integer pageSize, Integer pageNum, Integer userId) {
        LambdaQueryWrapper<WgInfos> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WgInfos::getCreatorId, userId);
        Page<WgInfos> wgPage = new Page<>(pageNum, pageSize);
        page(wgPage, queryWrapper);
        List<WgInfos> records = wgPage.getRecords();
        records = putInfo(records);
        PageVo<WgInfos> pageVo = new PageVo<>(records, wgPage.getTotal());
        return R.ok(pageVo);
    }

    @Override
    public R<PageVo<WgInfos>> findJoinedWGById(Integer pageSize, Integer pageNum, Integer userId) {
        // 查找我加入的任务，从子任务开始找
        Page<Subtask> subtaskPage = subtaskService.selectByAssignId(Long.valueOf(userId), pageSize, pageNum);
        List<Subtask> subtasks = subtaskPage.getRecords();
        if(subtasks.size() == 0) {
            return R.ok(new PageVo<>(new ArrayList<>(), 0L));
        }
        List<Long> wgIds = new ArrayList<>();
        subtasks.forEach(subtask -> wgIds.add(subtask.getWgId()));
        // 查找到任务后，再去查询任务的相关信息
        List<WgInfos> records = wgInfoMapper.selectBatchIds(wgIds);
        records = putInfo(records);
        PageVo<WgInfos> pageVo = new PageVo<>(records, subtaskPage.getTotal());
        return R.ok(pageVo);
    }

    @Override
    public R<PageVo<WgInfos>> findFocusedWGById(Integer pageSize, Integer pageNum, Integer userId) {
        // 查找我关注的任务
        Page<Focus> focusPage = focusService.selectByUserId(userId, pageSize, pageNum);
        List<Focus> focus = focusPage.getRecords();
        if(focus.size() == 0) {
            return R.ok(new PageVo<>(new ArrayList<>(), 0L));
        }
        List<Long> wgIds = new ArrayList<>();
        focus.forEach(f -> wgIds.add(f.getWgId()));
        List<WgInfos> records = wgInfoMapper.selectBatchIds(wgIds);
        records = putInfo(records);
        PageVo<WgInfos> pageVo = new PageVo<>(records, focusPage.getTotal());
        return R.ok(pageVo);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public R addWG(WgInfoAddDto wgInfo) {
        WgInfos newWg = WgUtil.copyObject(wgInfo, WgInfos.class);
        save(newWg);
        // 默认给创建者创建一个子任务
        Subtask subtask = new Subtask();
        subtask.setWgId(newWg.getId()).setAssignId(newWg.getCreatorId());
        subtaskService.save(subtask);
        return R.ok();
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public R completeWG(SubTaskUpdateVo subtask) {
        // 先根据wgId和assignId找到子任务id，更新子任务的状态
        LambdaQueryWrapper<Subtask> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Subtask::getWgId, subtask.getWgId()).eq(Subtask::getAssignId, subtask.getAssignId());
        Subtask dbTask = subtaskService.getOne(wrapper);
        if(dbTask != null) {
            dbTask.setStatus(subtask.getStatus());
            subtaskService.updateById(dbTask);
            // 加一下积分
            scoreService.addScore(subtask.getAssignId());
        }
        // 如果这是最后一个子任务完成，则把父任务也完成
        wrapper.clear();
        wrapper.eq(Subtask::getWgId, subtask.getWgId()).eq(Subtask::getStatus, 0);
        List<Subtask> activeTasks = subtaskService.list(wrapper);
        if(activeTasks.size() == 0) {
            WgInfos wg = new WgInfos();
            wg.setId(subtask.getWgId()).setStatus(1);
            updateById(wg);
        }
        return R.ok();
    }

    @Override
    public R<PageVo<WgInfos>> queryWG(Integer pageSize, Integer pageNum, String startTime, String endTime,
                                      String creator, Long focusUserId, Boolean focusFlag, String wgName) {
        LambdaQueryWrapper<WgInfos> wrapper = new LambdaQueryWrapper<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        if(startTime != null && !startTime.trim().equals("")) {
            try {
                wrapper.ge(WgInfos::getStartTime, sdf.parse(startTime));
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        }
        if(endTime != null && !endTime.trim().equals("")) {
            try {
                // 前端传递的只有年月，那么转化出来的日期就为每个月的第一天
                // 将月份加一，然后查询的时候小于这个日期
                Date endDate = sdf.parse(endTime);
                endDate.setMonth(endDate.getMonth() + 1);
                wrapper.lt(WgInfos::getEndTime, endDate);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        }
        if(wgName != null && !wgName.trim().equals("")) {
            wrapper.like(WgInfos::getName, wgName.trim());
        }
        List<WgInfos> wgs = list(wrapper);
        wgs = wgs.stream().filter(
                wg -> checkCreator(wg.getCreatorId(), creator) && checkFocus(wg.getId(), focusUserId, focusFlag)
        ).collect(Collectors.toList());
        // 做一个分页
        int startIndex = pageSize * (pageNum - 1);
        int endIndex = pageSize * pageNum;
        endIndex = Math.min(endIndex, wgs.size());
        startIndex = Math.min(startIndex, wgs.size());
        List<WgInfos> wgInfos = wgs.subList(startIndex, endIndex);
        wgInfos = putInfo(wgInfos);
        PageVo<WgInfos> pageVo = new PageVo<>(wgInfos, (long) wgs.size());
        return R.ok(pageVo);
    }

    @Override
    public R<WgInfos> getWgById(Long id) {
        WgInfos wg = getById(id);
        wg.setCreatorName(userService.getById(wg.getCreatorId()).getName())
                .setSubtaskList(subtaskService.getByWgId(wg.getId()))
                .setFocusList(focusService.getFocusByWg(wg.getId()))
                .setApplysList(applyService.getApplyByWg(wg.getId()));
        return R.ok(wg);
    }

    @Override
    public R<List<Subtask>> getMembers(Integer wgId) {
        WgInfos wg = getById(wgId);
        List<Subtask> subtasks = subtaskService.getByWgId(wg.getId());
        subtasks = subtasks.stream().map(
                task -> {
                    Users user = userService.getById(task.getAssignId());
                    Depts dept = deptService.getById(user.getDeptId());
                    task.setUserName(user.getName()).setEmail(user.getEmail());
                    if (dept != null) {
                        task.setDept(dept.getName());
                    }
                    return task;
                }
        ).collect(Collectors.toList());
        return R.ok(subtasks);
    }

    @Override
    public R deleteMember(SubTaskVo task) {
        Subtask subtask = new Subtask();
        subtask.setWgId(task.getWgId()).setAssignId(task.getAssignId());
        LambdaQueryWrapper<Subtask> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Subtask::getAssignId, task.getAssignId()).eq(Subtask::getWgId, task.getWgId());
        subtaskService.remove(wrapper);
        return R.ok();
    }

    public boolean checkCreator(Long creatorId, String creator) {
        if(creator == null || creator.trim().equals("")) {
            return true;
        }
        Users user = userService.getById(creatorId);
        return user != null && user.getName().contains(creator);
    }

    public boolean checkFocus(Long id, Long focusUserId, Boolean focusFlag) {
        if(focusUserId == null || focusUserId == 0) {
            return true;
        }
        LambdaQueryWrapper<Focus> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Focus::getUserId, focusUserId).eq(Focus::getWgId, id);
        Focus focus = focusService.getOne(wrapper);
        return (focusFlag && focus != null) || (!focusFlag && focus==null);
    }

    public List<WgInfos> putInfo(List<WgInfos> records) {
        return records.stream().map(wg ->
                wg.setCreatorName(userService.getById(wg.getCreatorId()).getName())
                        .setSubtaskList(subtaskService.getByWgId(wg.getId()))
                        .setFocusList(focusService.getFocusByWg(wg.getId()))
                        .setApplysList(applyService.getApplyByWg(wg.getId()))
        ).collect(Collectors.toList());
    }
}
